import {
  type Address,
  type Hex,
  encodeAbiParameters,
  getAbiItem,
  parseAbiParameters,
  zeroAddress,
} from "viem";
import { assertType, describe, expect, test } from "vitest";
import { decodeAbiParameters } from "./decodeAbiParameters.js";
import { toLowerCase } from "./lowercase.js";

/** Imported from Viem: https://github.com/wevm/viem/blob/38525bf1d55ec3fe0569e47700c7f9e70d3c971c/src/utils/abi/decodeAbiParameters.test.ts */

describe("static", () => {
  test("blank", () => {
    const result = decodeAbiParameters([], "0x");
    assertType<readonly []>(result);
    expect(result).toEqual([]);
  });

  test("uint", () => {
    const result = decodeAbiParameters(
      [{ type: "uint" }],
      "0x0000000000000000000000000000000000000000000000000000000000010f2c",
    );
    assertType<readonly [bigint]>(result);
    expect(result).toEqual([69420n]);
  });

  test("uint8", () => {
    const result = decodeAbiParameters(
      parseAbiParameters("uint8"),
      "0x0000000000000000000000000000000000000000000000000000000000000020",
    );
    assertType<readonly [number]>(result);
    expect(result).toEqual([32]);
  });

  test("uint32", () => {
    const result = decodeAbiParameters(
      parseAbiParameters("uint32"),
      "0x0000000000000000000000000000000000000000000000000000000000010f2c",
    );
    assertType<readonly [number]>(result);
    expect(result).toEqual([69420]);
  });

  describe("int", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("int"),
        "0x0000000000000000000000000000000000000000000000000000000000010f2c",
      );
      assertType<readonly [bigint]>(result);
      expect(result).toEqual([69420n]);
    });

    test("negative (twos compliment)", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("int"),
        "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffef0d4",
      );
      assertType<readonly [bigint]>(result);
      expect(result).toEqual([-69420n]);
    });
  });

  describe("int8", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("int8"),
        "0x000000000000000000000000000000000000000000000000000000000000007f",
      );
      assertType<readonly [number]>(result);
      expect(result).toEqual([127]);
    });

    test("negative (twos compliment)", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("int8"),
        "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80",
      );
      assertType<readonly [number]>(result);
      expect(result).toEqual([-128]);
    });
  });

  describe("int32", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("int32"),
        "0x000000000000000000000000000000000000000000000000000000007fffffff",
      );
      assertType<readonly [number]>(result);
      expect(result).toEqual([2147483647]);
    });

    test("negative (twos compliment)", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("int32"),
        "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000",
      );
      assertType<readonly [number]>(result);
      expect(result).toEqual([-2147483648]);
    });
  });

  describe("address", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("address"),
        "0x00000000000000000000000014dc79964da2c08b23698b3d3cc7ca32193d9955",
        { formatAddress: toLowerCase },
      );
      assertType<readonly [Address]>(result);
      expect(
        decodeAbiParameters(
          parseAbiParameters("address"),
          "0x00000000000000000000000014dc79964da2c08b23698b3d3cc7ca32193d9955",
          { formatAddress: toLowerCase },
        ),
      ).toMatchInlineSnapshot(`
        [
          "0x14dc79964da2c08b23698b3d3cc7ca32193d9955",
        ]
      `);
    });
  });

  describe("bytes8", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("bytes8"),
        "0x0123456789abcdef000000000000000000000000000000000000000000000000",
      );
      assertType<readonly [Hex]>(result);
      expect(result).toEqual(["0x0123456789abcdef"]);
    });
  });

  describe("bytes16", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("bytes16"),
        "0x0123456789abcdef0123456789abcdef00000000000000000000000000000000",
      );
      assertType<readonly [Hex]>(result);
      expect(result).toEqual(["0x0123456789abcdef0123456789abcdef"]);
    });
  });

  describe("uint[3]", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("uint256[3]"),
        "0x0000000000000000000000000000000000000000000000000000000000010f2c000000000000000000000000000000000000000000000000000000000000a45500000000000000000000000000000000000000000000000000000000190f1b44",
      );
      assertType<readonly [readonly [bigint, bigint, bigint]]>(result);
      expect(result).toEqual([[69420n, 42069n, 420420420n]]);
    });
  });

  describe("int[3]", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("int[3]"),
        "0x0000000000000000000000000000000000000000000000000000000000010f2cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5bab00000000000000000000000000000000000000000000000000000000190f1b44",
      );
      assertType<readonly [readonly [bigint, bigint, bigint]]>(result);
      expect(result).toEqual([[69420n, -42069n, 420420420n]]);
    });
  });

  describe("address[2]", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("address[2]"),
        "0x000000000000000000000000c961145a54c96e3ae9baa048c4f4d6b04c13916b000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac",
        { formatAddress: toLowerCase },
      );
      assertType<readonly [readonly [Address, Address]]>(result);
      expect(result).toMatchInlineSnapshot(`
        [
          [
            "0xc961145a54c96e3ae9baa048c4f4d6b04c13916b",
            "0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac",
          ],
        ]
      `);
    });
  });

  describe("bool[2]", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("bool[2]"),
        "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000",
      );
      assertType<readonly [readonly [boolean, boolean]]>(result);
      expect(result).toEqual([[true, false]]);
    });
  });

  describe("uint[3][2]", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("uint256[3][2]"),
        "0x0000000000000000000000000000000000000000000000000000000000010f2c000000000000000000000000000000000000000000000000000000000000a45500000000000000000000000000000000000000000000000000000000190f1b4400000000000000000000000000000000000000000000000000000000000001a4000000000000000000000000000000000000000000000000000000000000002c00000000000000000000000000000000000000000000000000000000000001a6",
      );
      assertType<
        readonly [
          readonly [
            readonly [bigint, bigint, bigint],
            readonly [bigint, bigint, bigint],
          ],
        ]
      >(result);
      expect(result).toEqual([
        [
          [69420n, 42069n, 420420420n],
          [420n, 44n, 422n],
        ],
      ]);
    });
  });

  describe("uint[3][2][4]", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("uint[3][2][4]"),
        "0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001300000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000015000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000018",
      );
      assertType<
        readonly [
          readonly [
            readonly [
              readonly [bigint, bigint, bigint],
              readonly [bigint, bigint, bigint],
            ],
            readonly [
              readonly [bigint, bigint, bigint],
              readonly [bigint, bigint, bigint],
            ],
            readonly [
              readonly [bigint, bigint, bigint],
              readonly [bigint, bigint, bigint],
            ],
            readonly [
              readonly [bigint, bigint, bigint],
              readonly [bigint, bigint, bigint],
            ],
          ],
        ]
      >(result);
      expect(result).toEqual([
        [
          [
            [1n, 2n, 3n],
            [4n, 5n, 6n],
          ],
          [
            [7n, 8n, 9n],
            [10n, 11n, 12n],
          ],
          [
            [13n, 14n, 15n],
            [16n, 17n, 18n],
          ],
          [
            [19n, 20n, 21n],
            [22n, 23n, 24n],
          ],
        ],
      ]);
    });
  });

  describe("struct: (uint256,bool,address)", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("(uint256 x, bool y, address z)"),
        "0x00000000000000000000000000000000000000000000000000000000000001a40000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac",
        { formatAddress: toLowerCase },
      );
      assertType<
        readonly [
          {
            x: bigint;
            y: boolean;
            z: Hex;
          },
        ]
      >(result);
      expect(result).toMatchInlineSnapshot(`
        [
          {
            "x": 420n,
            "y": true,
            "z": "0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac",
          },
        ]
      `);
    });
  });

  describe("struct: (uint256,bool,address)", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("(uint256, bool, address)"),
        "0x00000000000000000000000000000000000000000000000000000000000001a40000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac",
        { formatAddress: toLowerCase },
      );
      assertType<readonly [readonly [bigint, boolean, Hex]]>(result);
      expect(result).toMatchInlineSnapshot(`
        [
          [
            420n,
            true,
            "0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac",
          ],
        ]
      `);
    });
  });

  describe("struct: (uint256,bool,address)", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("(uint256 x, bool, address z)"),
        "0x00000000000000000000000000000000000000000000000000000000000001a40000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac",
        { formatAddress: toLowerCase },
      );
      assertType<readonly [readonly [bigint, boolean, Hex]]>(result);
      expect(result).toMatchInlineSnapshot(`
        [
          [
            420n,
            true,
            "0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac",
          ],
        ]
      `);
    });
  });

  describe("struct: ()", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        [{ type: "tuple", components: [] }],
        "0x00000000000000000000000000000000000000000000000000000000000001a40000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac",
      );
      assertType<readonly [readonly []]>(result);
      expect(result).toEqual([[]]);
    });
  });

  describe("struct: ((uint256,bool,address),(uint256,bool,address),uint8[2])", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters(
          "((uint256 x,bool y,address z) foo,(uint256 x,bool y,address z) baz,uint8[2] x)",
        ),
        "0x00000000000000000000000000000000000000000000000000000000000001a40000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac00000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c961145a54c96e3ae9baa048c4f4d6b04c13916b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
        { formatAddress: toLowerCase },
      );
      assertType<
        readonly [
          {
            foo: {
              x: bigint;
              y: boolean;
              z: Hex;
            };
            baz: {
              x: bigint;
              y: boolean;
              z: Hex;
            };
            x: readonly [number, number];
          },
        ]
      >(result);
      expect(result).toMatchInlineSnapshot(`
        [
          {
            "baz": {
              "x": 69n,
              "y": false,
              "z": "0xc961145a54c96e3ae9baa048c4f4d6b04c13916b",
            },
            "foo": {
              "x": 420n,
              "y": true,
              "z": "0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac",
            },
            "x": [
              1,
              2,
            ],
          },
        ]
      `);
    });
  });

  describe("uint256[2],bool,string[3]", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("uint256[2],bool,string[3]"),
        "0x00000000000000000000000000000000000000000000000000000000000001a4000000000000000000000000000000000000000000000000000000000000004500000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000057761676d6900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047669656d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036c6f6c0000000000000000000000000000000000000000000000000000000000",
      );
      assertType<
        readonly [
          readonly [bigint, bigint],
          boolean,
          readonly [string, string, string],
        ]
      >(result);
      expect(result).toEqual([[420n, 69n], true, ["wagmi", "viem", "lol"]]);
    });
  });

  describe("uint256[2],bool,string[3]", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("uint256[2],bool,string[3]"),
        "0x00000000000000000000000000000000000000000000000000000000000001a4000000000000000000000000000000000000000000000000000000000000004500000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000057761676d6900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047669656d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036c6f6c0000000000000000000000000000000000000000000000000000000000",
      );
      assertType<
        readonly [
          readonly [bigint, bigint],
          boolean,
          readonly [string, string, string],
        ]
      >(result);
      expect(result).toEqual([[420n, 69n], true, ["wagmi", "viem", "lol"]]);
    });
  });

  describe("uint,bool,address", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("uint,bool,address"),
        "0x00000000000000000000000000000000000000000000000000000000000001a40000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c961145a54c96e3ae9baa048c4f4d6b04c13916b",
        { formatAddress: toLowerCase },
      );
      assertType<readonly [bigint, boolean, string]>(result);
      expect(result).toMatchInlineSnapshot(`
        [
          420n,
          true,
          "0xc961145a54c96e3ae9baa048c4f4d6b04c13916b",
        ]
      `);
    });
  });
});

describe("dynamic", () => {
  describe("string", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("string"),
        "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000057761676d69000000000000000000000000000000000000000000000000000000",
      );
      assertType<readonly [string]>(result);
      expect(result).toEqual(["wagmi"]);
    });

    test("empty", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("string"),
        "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000",
      );
      assertType<readonly [string]>(result);
      expect(result).toEqual([""]);
    });

    test("default", () => {
      expect(
        decodeAbiParameters(
          parseAbiParameters("string"),
          "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002da4c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e73656374657475722061646970697363696e6720656c69742e204e756e63206661756369627573206c6f72656d2061206c696265726f20617563746f7220636f6e64696d656e74756d2e20446f6e6563206f726e617265206d617373612072686f6e637573206c616375732072757472756d2c20656765742070756c76696e6172206172637520656c656d656e74756d2e204e756e63206d6175726973206c6f72656d2c20736f64616c65732065676574207669766572726120696e2c20657569736d6f642071756973206d692e205072616573656e74206e656320636f6d6d6f646f206c656f2e2050686173656c6c757320636f6e64696d656e74756d206d61757269732073656420616363756d73616e20656c656966656e642e205072616573656e7420616320626c616e6469742073656d2c2065742072757472756d20697073756d2e20457469616d20696e2074656c6c757320616320656e696d20666163696c6973697320756c7472696365732e20467573636520616320766573746962756c756d207175616d2e204475697320736564207075727573207363656c657269737175652c20736f6c6c696369747564696e20657261742061632c2070756c76696e6172206e6973692e2050656c6c656e746573717565206575207075727573206e65632073617069656e207665686963756c6120636f6e76616c6c69732075742076656c20656c69742e2053757370656e6469737365206567657420657820766974616520656e696d20766f6c7574706174207363656c657269737175652e20536564207175697320656c6974207472697374697175652065726174206c756374757320656765737461732061206163206f64696f2e2044756973207665686963756c6120656e696d206163206d6574757320677261766964612c2076656c206d6178696d7573206e69736920696d706572646965742e000000000000",
        ),
      ).toMatchInlineSnapshot(
        `
        [
          "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc faucibus lorem a libero auctor condimentum. Donec ornare massa rhoncus lacus rutrum, eget pulvinar arcu elementum. Nunc mauris lorem, sodales eget viverra in, euismod quis mi. Praesent nec commodo leo. Phasellus condimentum mauris sed accumsan eleifend. Praesent ac blandit sem, et rutrum ipsum. Etiam in tellus ac enim facilisis ultrices. Fusce ac vestibulum quam. Duis sed purus scelerisque, sollicitudin erat ac, pulvinar nisi. Pellentesque eu purus nec sapien vehicula convallis ut vel elit. Suspendisse eget ex vitae enim volutpat scelerisque. Sed quis elit tristique erat luctus egestas a ac odio. Duis vehicula enim ac metus gravida, vel maximus nisi imperdiet.",
        ]
      `,
      );
    });

    test("emojis", () => {
      expect(
        decodeAbiParameters(
          parseAbiParameters("string"),
          "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000026f09f91a8e2808df09f91a8e2808df09f91a6e2808df09f91a6f09f8fb4e2808de298a0efb88f0000000000000000000000000000000000000000000000000000",
        ),
      ).toMatchInlineSnapshot(
        `
        [
          "👨‍👨‍👦‍👦🏴‍☠️",
        ]
      `,
      );
    });
  });

  describe("string,uint,bool", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("string,uint,bool"),
        "0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001a4000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000057761676d69000000000000000000000000000000000000000000000000000000",
      );
      assertType<readonly [string, bigint, boolean]>(result);
      expect(result).toEqual(["wagmi", 420n, true]);
    });
  });

  describe("uint[2],bool,string", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("uint[2],bool,string"),
        "0x00000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000057761676d69000000000000000000000000000000000000000000000000000000",
      );
      assertType<readonly [readonly [bigint, bigint], boolean, string]>(result);
      expect(result).toEqual([[420n, 69n], true, "wagmi"]);
    });
  });

  describe("bytes", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("bytes"),
        "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000030420690000000000000000000000000000000000000000000000000000000000",
      );
      assertType<readonly [Hex]>(result);
      expect(result).toEqual(["0x042069"]);
    });
  });

  describe("(uint256[][2])", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("uint256[][2]"),
        "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001",
      );
      assertType<readonly [readonly [readonly bigint[], readonly bigint[]]]>(
        result,
      );
      expect(result).toEqual([
        [
          [1n, 2n, 3n, 4n],
          [3n, 2n, 1n],
        ],
      ]);
    });
  });

  describe("uint256[2][][2]", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("uint256[2][][2]"),
        "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b",
      );
      assertType<
        readonly [
          readonly [
            readonly (readonly [bigint, bigint])[],
            readonly (readonly [bigint, bigint])[],
          ],
        ]
      >(result);
      expect(result).toEqual([
        [
          [
            [1n, 2n],
            [4n, 5n],
          ],
          [
            [8n, 9n],
            [10n, 11n],
          ],
        ],
      ]);
    });
  });

  describe("uint256[][][2]", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("uint256[][][2]"),
        "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a",
      );
      assertType<
        readonly [
          readonly [
            readonly (readonly bigint[])[],
            readonly (readonly bigint[])[],
          ],
        ]
      >(result);
      expect(result).toEqual([
        [
          [
            [1n, 2n, 3n],
            [4n, 5n, 6n, 7n],
          ],
          [[8n], [9n, 10n]],
        ],
      ]);
    });
  });

  describe("uint256[][1][1]", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("uint256[][1][1]"),
        "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003",
      );
      assertType<readonly [readonly [readonly [readonly bigint[]]]]>(result);
      expect(result).toEqual([[[[1n, 2n, 3n]]]]);
    });
  });

  describe("(uint256[][2][2])", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("uint256[][2][2]"),
        "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000007000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a",
      );
      assertType<
        readonly [
          readonly [
            readonly [readonly bigint[], readonly bigint[]],
            readonly [readonly bigint[], readonly bigint[]],
          ],
        ]
      >(result);
      expect(result).toEqual([
        [
          [
            [1n, 2n, 3n],
            [4n, 5n, 6n, 7n],
          ],
          [[8n], [9n, 10n]],
        ],
      ]);
    });
  });

  describe("(uint256[][3][2])", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("uint256[][3][2]"),
        "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000007000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000b0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000011",
      );
      assertType<
        readonly [
          readonly [
            readonly [readonly bigint[], readonly bigint[], readonly bigint[]],
            readonly [readonly bigint[], readonly bigint[], readonly bigint[]],
          ],
        ]
      >(result);
      expect(result).toEqual([
        [
          [
            [1n, 2n, 3n],
            [4n, 5n, 6n, 7n],
            [8n, 9n, 10n],
          ],
          [[11n], [12n, 13n], [14n, 15n, 16n, 17n]],
        ],
      ]);
    });
  });

  describe("(uint256[][2][3])", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("uint256[][2][3]"),
        "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000007000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000011",
      );
      assertType<
        readonly [
          readonly [
            readonly [readonly bigint[], readonly bigint[]],
            readonly [readonly bigint[], readonly bigint[]],
            readonly [readonly bigint[], readonly bigint[]],
          ],
        ]
      >(result);
      expect(result).toEqual([
        [
          [
            [1n, 2n],
            [3n, 4n, 5n],
          ],
          [
            [6n, 7n, 8n],
            [9n, 10n],
          ],
          [
            [11n, 12n, 13n],
            [14n, 15n, 16n, 17n],
          ],
        ],
      ]);
    });
  });

  describe("(uint256[][2][3][4])", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("uint256[][2][3][4]"),
        "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000007c00000000000000000000000000000000000000000000000000000000000000b80000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000007000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000d0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000007000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000002e0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000006",
      );
      assertType<
        readonly [
          readonly [
            readonly [
              readonly [readonly bigint[], readonly bigint[]],
              readonly [readonly bigint[], readonly bigint[]],
              readonly [readonly bigint[], readonly bigint[]],
            ],
            readonly [
              readonly [readonly bigint[], readonly bigint[]],
              readonly [readonly bigint[], readonly bigint[]],
              readonly [readonly bigint[], readonly bigint[]],
            ],
            readonly [
              readonly [readonly bigint[], readonly bigint[]],
              readonly [readonly bigint[], readonly bigint[]],
              readonly [readonly bigint[], readonly bigint[]],
            ],
            readonly [
              readonly [readonly bigint[], readonly bigint[]],
              readonly [readonly bigint[], readonly bigint[]],
              readonly [readonly bigint[], readonly bigint[]],
            ],
          ],
        ]
      >(result);
      expect(result).toMatchInlineSnapshot(`
        [
          [
            [
              [
                [
                  1n,
                  2n,
                  3n,
                ],
                [
                  4n,
                  5n,
                  6n,
                  7n,
                ],
              ],
              [
                [
                  8n,
                ],
                [
                  9n,
                  10n,
                ],
              ],
              [
                [
                  11n,
                  12n,
                ],
                [
                  13n,
                ],
              ],
            ],
            [
              [
                [
                  14n,
                  15n,
                ],
                [
                  16n,
                  17n,
                  18n,
                ],
              ],
              [
                [
                  0n,
                  1n,
                ],
                [
                  2n,
                  3n,
                  4n,
                ],
              ],
              [
                [
                  5n,
                  6n,
                ],
                [
                  1n,
                  2n,
                  1n,
                ],
              ],
            ],
            [
              [
                [
                  1n,
                  2n,
                  1n,
                  2n,
                ],
                [
                  1n,
                  5n,
                  6n,
                ],
              ],
              [
                [
                  1n,
                ],
                [
                  2n,
                ],
              ],
              [
                [
                  1n,
                  2n,
                  3n,
                ],
                [
                  5n,
                  6n,
                  7n,
                ],
              ],
            ],
            [
              [
                [
                  9n,
                  8n,
                  7n,
                ],
                [
                  5n,
                  5n,
                  5n,
                ],
              ],
              [
                [
                  1n,
                  2n,
                  3n,
                ],
                [
                  4n,
                  4n,
                  4n,
                ],
              ],
              [
                [
                  5n,
                  5n,
                  5n,
                ],
                [
                  6n,
                  6n,
                  6n,
                ],
              ],
            ],
          ],
        ]
      `);
    });
  });

  describe("(uint256[2][][2])", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("uint256[2][][2]"),
        "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b0000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a",
      );
      assertType<
        readonly [
          readonly [
            readonly (readonly [bigint, bigint])[],
            readonly (readonly [bigint, bigint])[],
          ],
        ]
      >(result);
      expect(result).toEqual([
        [
          [
            [1n, 2n],
            [4n, 5n],
          ],
          [
            [8n, 9n],
            [10n, 11n],
            [9n, 10n],
          ],
        ],
      ]);
    });
  });

  describe("(uint[])", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("uint256[]"),
        "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000001a4000000000000000000000000000000000000000000000000000000000000004500000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000037",
      );
      assertType<readonly [readonly bigint[]]>(result);
      expect(result).toEqual([[420n, 69n, 22n, 55n]]);
    });

    test("empty", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("uint256[]"),
        "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000",
      );
      assertType<readonly [readonly bigint[]]>(result);
      expect(result).toEqual([[]]);
    });
  });

  describe("(uint[][])", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("uint256[][]"),
        "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000001a40000000000000000000000000000000000000000000000000000000000000045",
      );
      assertType<readonly [readonly (readonly bigint[])[]]>(result);
      expect(result).toEqual([[[420n, 69n]]]);
    });

    test("empty", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("uint256[][]"),
        "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000",
      );
      assertType<readonly [readonly (readonly bigint[])[]]>(result);
      expect(result).toEqual([[[]]]);
    });

    // cast abi-encode "a(uint[][])" "[[420,69],[22,55,22],[51,52,66,11]]"
    test("complex", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("uint256[][]"),
        "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000001a4000000000000000000000000000000000000000000000000000000000000004500000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000003700000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000000000000000000000000000000000b",
      );
      assertType<readonly [readonly (readonly bigint[])[]]>(result);
      expect(result).toEqual([
        [
          [420n, 69n],
          [22n, 55n, 22n],
          [51n, 52n, 66n, 11n],
        ],
      ]);
    });
  });

  describe("(string[2])", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("string[2]"),
        "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000057761676d6900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047669656d00000000000000000000000000000000000000000000000000000000",
      );
      assertType<readonly [readonly [string, string]]>(result);
      expect(result).toEqual([["wagmi", "viem"]]);
    });
  });

  describe("(string[2][3])", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("string[2][3]"),
        "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000057761676d6900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047669656d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000046a616b65000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003746f6d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000036c6f6c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046861686100000000000000000000000000000000000000000000000000000000",
      );
      assertType<readonly [readonly (readonly [string, string])[]]>(result);
      expect(result).toEqual([
        [
          ["wagmi", "viem"],
          ["jake", "tom"],
          ["lol", "haha"],
        ],
      ]);
    });
  });

  describe("(bytes[2])", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("bytes[2]"),
        "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002123400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044141414100000000000000000000000000000000000000000000000000000000",
      );
      assertType<readonly [readonly [Hex, Hex]]>(result);
      expect(result).toEqual([["0x1234", "0x41414141"]]);
    });
  });

  describe("(uint256, string)", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("(uint256, string)"),
        "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000",
      );
      expect(result).toEqual([[23n, "hello"]]);
    });
  });

  describe("((uint256, string))", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("((uint256, string))"),
        "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000",
      );
      expect(result).toEqual([[[23n, "hello"]]]);
    });
  });

  describe("((uint256[], string))", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("((uint256[], string))"),
        "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000017000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000",
      );
      expect(result).toEqual([[[[23n, 46n], "hello"]]]);
    });
  });

  // cast abi-encode "a((uint256[],bool,string[]))" "([1,2,3,4],true,[hello,world])"
  describe("(uint256[],bool,string[])", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("(uint256[] x,bool y,string[] z)"),
        "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000568656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005776f726c64000000000000000000000000000000000000000000000000000000",
      );
      assertType<
        readonly [
          {
            x: readonly bigint[];
            y: boolean;
            z: readonly string[];
          },
        ]
      >(result);
      expect(result).toEqual([
        {
          x: [1n, 2n, 3n, 4n],
          y: true,
          z: ["hello", "world"],
        },
      ]);
    });
  });

  describe("((uint256[] x,bool y,string[] z) foo,uint256 a,string[] b)", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters(
          "((uint256[] x,bool y,string[] z) foo,uint256 a,string[] b)",
        ),
        "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001a4000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000568656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005776f726c6400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000057761676d6900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047669656d00000000000000000000000000000000000000000000000000000000",
      );
      assertType<
        readonly [
          {
            foo: {
              x: readonly bigint[];
              y: boolean;
              z: readonly string[];
            };
            a: bigint;
            b: readonly string[];
          },
        ]
      >(result);
      expect(result).toEqual([
        {
          foo: {
            x: [1n, 2n, 3n, 4n],
            y: true,
            z: ["hello", "world"],
          },
          a: 420n,
          b: ["wagmi", "viem"],
        },
      ]);
    });
  });

  describe("((uint256[],bool,string[]) foo,uint256,string[])", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters("((uint256[],bool,string[]) foo,uint256,string[])"),
        "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001a4000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000568656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005776f726c6400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000057761676d6900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047669656d00000000000000000000000000000000000000000000000000000000",
      );
      assertType<
        readonly [
          readonly [
            readonly [readonly bigint[], boolean, readonly string[]],
            bigint,
            readonly string[],
          ],
        ]
      >(result);
      expect(result).toEqual([
        [[[1n, 2n, 3n, 4n], true, ["hello", "world"]], 420n, ["wagmi", "viem"]],
      ]);
    });
  });

  describe("(uint256[],bool,string[]),(((uint256[],bool,string[]),uint256,string[]),((uint256[],bool,string[]), uint256, string[]),uint256,string[])", () => {
    test("default", () => {
      const result = decodeAbiParameters(
        parseAbiParameters(
          "(uint256[] x, bool y, string[] z) bazIn, (((uint256[] x, bool y, string[] z) foo, uint256 a, string[] b) foo, ((uint256[] x, bool y, string[] z) foo, uint256 a, string[] b) bar, uint256 c, string[] d) gmiIn",
        ),
        "0x0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000568656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005776f726c640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000004026aa0000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000001a4000000000000000000000000000000000000000000000000000000000000004500000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000046e696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004686168610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000057761676d690000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006616c6c646179000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000010f2c00000000000000000000000000000000000000000000000000000000000002c00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001a40000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000004746869730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000026973000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000161000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005706172616d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000568656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005746865726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000036c6f6c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046861686100000000000000000000000000000000000000000000000000000000",
      );
      assertType<
        readonly [
          {
            x: readonly bigint[];
            y: boolean;
            z: readonly string[];
          },
          {
            foo: {
              foo: {
                x: readonly bigint[];
                y: boolean;
                z: readonly string[];
              };
              a: bigint;
              b: readonly string[];
            };
            bar: {
              foo: {
                x: readonly bigint[];
                y: boolean;
                z: readonly string[];
              };
              a: bigint;
              b: readonly string[];
            };
            c: bigint;
            d: readonly string[];
          },
        ]
      >(result);
      expect(result).toEqual([
        {
          x: [1n, 2n, 3n, 4n],
          y: true,
          z: ["hello", "world"],
        },
        {
          foo: {
            a: 420n,
            b: ["wagmi", "allday"],
            foo: {
              x: [420n, 69n],
              y: true,
              z: ["nice", "haha"],
            },
          },
          bar: {
            a: 69420n,
            b: ["hello", "there"],
            foo: {
              x: [420n, 420n],
              y: true,
              z: ["this", "is", "a", "param"],
            },
          },
          c: 4204202n,
          d: ["lol", "haha"],
        },
      ]);
    });
  });
});

const seaportContractConfigAbi = [
  {
    inputs: [
      {
        components: [
          { name: "offerer", type: "address" },
          { name: "zone", type: "address" },
          {
            components: [
              {
                name: "itemType",
                type: "uint8",
              },
              { name: "token", type: "address" },
              {
                name: "identifierOrCriteria",
                type: "uint256",
              },
              {
                name: "startAmount",
                type: "uint256",
              },
              { name: "endAmount", type: "uint256" },
            ],

            name: "offer",
            type: "tuple[]",
          },
          {
            components: [
              {
                name: "itemType",
                type: "uint8",
              },
              { name: "token", type: "address" },
              {
                name: "identifierOrCriteria",
                type: "uint256",
              },
              {
                name: "startAmount",
                type: "uint256",
              },
              { name: "endAmount", type: "uint256" },
              {
                name: "recipient",
                type: "address",
              },
            ],

            name: "consideration",
            type: "tuple[]",
          },
          {
            name: "orderType",
            type: "uint8",
          },
          { name: "startTime", type: "uint256" },
          { name: "endTime", type: "uint256" },
          { name: "zoneHash", type: "bytes32" },
          { name: "salt", type: "uint256" },
          { name: "conduitKey", type: "bytes32" },
          { name: "counter", type: "uint256" },
        ],

        name: "orders",
        type: "tuple[]",
      },
    ],
    name: "cancel",
    outputs: [{ name: "cancelled", type: "bool" }],
    stateMutability: "nonpayable",
    type: "function",
  },
  {
    inputs: [
      {
        components: [
          {
            components: [
              { name: "offerer", type: "address" },
              { name: "zone", type: "address" },
              {
                components: [
                  {
                    name: "itemType",
                    type: "uint8",
                  },
                  { name: "token", type: "address" },
                  {
                    name: "identifierOrCriteria",
                    type: "uint256",
                  },
                  {
                    name: "startAmount",
                    type: "uint256",
                  },
                  {
                    name: "endAmount",
                    type: "uint256",
                  },
                ],

                name: "offer",
                type: "tuple[]",
              },
              {
                components: [
                  {
                    name: "itemType",
                    type: "uint8",
                  },
                  { name: "token", type: "address" },
                  {
                    name: "identifierOrCriteria",
                    type: "uint256",
                  },
                  {
                    name: "startAmount",
                    type: "uint256",
                  },
                  {
                    name: "endAmount",
                    type: "uint256",
                  },
                  {
                    name: "recipient",
                    type: "address",
                  },
                ],

                name: "consideration",
                type: "tuple[]",
              },
              {
                name: "orderType",
                type: "uint8",
              },
              { name: "startTime", type: "uint256" },
              { name: "endTime", type: "uint256" },
              { name: "zoneHash", type: "bytes32" },
              { name: "salt", type: "uint256" },
              {
                name: "conduitKey",
                type: "bytes32",
              },
              {
                name: "totalOriginalConsiderationItems",
                type: "uint256",
              },
            ],

            name: "parameters",
            type: "tuple",
          },
          { name: "numerator", type: "uint120" },
          { name: "denominator", type: "uint120" },
          { name: "signature", type: "bytes" },
          { name: "extraData", type: "bytes" },
        ],

        name: "advancedOrder",
        type: "tuple",
      },
      {
        components: [
          { name: "orderIndex", type: "uint256" },
          { name: "side", type: "uint8" },
          { name: "index", type: "uint256" },
          { name: "identifier", type: "uint256" },
          {
            name: "criteriaProof",
            type: "bytes32[]",
          },
        ],

        name: "criteriaResolvers",
        type: "tuple[]",
      },
      {
        name: "fulfillerConduitKey",
        type: "bytes32",
      },
      { name: "recipient", type: "address" },
    ],
    name: "fulfillAdvancedOrder",
    outputs: [{ name: "fulfilled", type: "bool" }],
    stateMutability: "payable",
    type: "function",
  },
] as const;

describe("seaport", () => {
  test("cancel", () => {
    const cancel = getAbiItem({
      abi: seaportContractConfigAbi,
      name: "cancel",
    });
    const data = decodeAbiParameters(
      cancel.inputs,
      "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000540000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa9604500000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000001caab5c3b30000000000000000000000000000000000000000000000000000001caab5c3b3511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511a00000000000000000000000000000000000000000000000000000000498f3973511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511a00000000000000000000000000000000000000000000000000000000498f39730000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000001a4000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000005414d89a8bf7e99d732bc52f3e6a3ef461c0c07800000000000000000000000000000000000000000000000000000000000002030000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa9604500000000000000000000000000000000000000000000000000000000034fb5b7000000000000000000000000000000000000000000000000000000000000006f000000000000000000000000000000000000000000000000000000000001e0f30000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000001a4000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000037000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000008d000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa9604500000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000001caab5c3b30000000000000000000000000000000000000000000000000000001caab5c3b3511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511a00000000000000000000000000000000000000000000000000000000498f3973511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511a00000000000000000000000000000000000000000000000000000000498f39730000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000001a4000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000005414d89a8bf7e99d732bc52f3e6a3ef461c0c07800000000000000000000000000000000000000000000000000000000000002030000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa9604500000000000000000000000000000000000000000000000000000000034fb5b7000000000000000000000000000000000000000000000000000000000000006f000000000000000000000000000000000000000000000000000000000001e0f30000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000001a4000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000037000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000008d000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045",
      { formatAddress: toLowerCase },
    );
    expect(data).toMatchInlineSnapshot(`
      [
        [
          {
            "conduitKey": "0x511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511a",
            "consideration": [
              {
                "endAmount": 420n,
                "identifierOrCriteria": 69n,
                "itemType": 10,
                "recipient": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
                "startAmount": 6n,
                "token": "0x0000000000000000000000000000000000000000",
              },
              {
                "endAmount": 141n,
                "identifierOrCriteria": 55n,
                "itemType": 16,
                "recipient": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
                "startAmount": 15n,
                "token": "0x0000000000000000000000000000000000000000",
              },
            ],
            "counter": 1234123123n,
            "endTime": 123123123123n,
            "offer": [
              {
                "endAmount": 420n,
                "identifierOrCriteria": 69n,
                "itemType": 10,
                "startAmount": 6n,
                "token": "0x0000000000000000000000000000000000000000",
              },
              {
                "endAmount": 11n,
                "identifierOrCriteria": 515n,
                "itemType": 10,
                "startAmount": 6n,
                "token": "0x5414d89a8bf7e99d732bc52f3e6a3ef461c0c078",
              },
              {
                "endAmount": 123123n,
                "identifierOrCriteria": 55555511n,
                "itemType": 10,
                "startAmount": 111n,
                "token": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
              },
            ],
            "offerer": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
            "orderType": 10,
            "salt": 1234123123n,
            "startTime": 123123123123n,
            "zone": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
            "zoneHash": "0x511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511a",
          },
          {
            "conduitKey": "0x511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511a",
            "consideration": [
              {
                "endAmount": 420n,
                "identifierOrCriteria": 69n,
                "itemType": 10,
                "recipient": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
                "startAmount": 6n,
                "token": "0x0000000000000000000000000000000000000000",
              },
              {
                "endAmount": 141n,
                "identifierOrCriteria": 55n,
                "itemType": 16,
                "recipient": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
                "startAmount": 15n,
                "token": "0x0000000000000000000000000000000000000000",
              },
            ],
            "counter": 1234123123n,
            "endTime": 123123123123n,
            "offer": [
              {
                "endAmount": 420n,
                "identifierOrCriteria": 69n,
                "itemType": 10,
                "startAmount": 6n,
                "token": "0x0000000000000000000000000000000000000000",
              },
              {
                "endAmount": 11n,
                "identifierOrCriteria": 515n,
                "itemType": 10,
                "startAmount": 6n,
                "token": "0x5414d89a8bf7e99d732bc52f3e6a3ef461c0c078",
              },
              {
                "endAmount": 123123n,
                "identifierOrCriteria": 55555511n,
                "itemType": 10,
                "startAmount": 111n,
                "token": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
              },
            ],
            "offerer": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
            "orderType": 10,
            "salt": 1234123123n,
            "startTime": 123123123123n,
            "zone": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
            "zoneHash": "0x511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511a",
          },
        ],
      ]
    `);
  });

  test("fulfillAdvancedOrder", () => {
    const fulfillAdvancedOrder = getAbiItem({
      abi: seaportContractConfigAbi,
      name: "fulfillAdvancedOrder",
    });
    const data = decodeAbiParameters(
      fulfillAdvancedOrder.inputs,
      "0x000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000006a0511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511a000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa9604500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001a4000000000000000000000000000000000000000000000000000000000000004500000000000000000000000000000000000000000000000000000000000005a000000000000000000000000000000000000000000000000000000000000005e0000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa9604500000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000001caab5c3b30000000000000000000000000000000000000000000000000000001caab5c3b3511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511a00000000000000000000000000000000000000000000000000000000498f3973511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511a0000000000000000000000000000000000000000000000000000000000010f2c0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000001a4000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000005414d89a8bf7e99d732bc52f3e6a3ef461c0c07800000000000000000000000000000000000000000000000000000000000002030000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa9604500000000000000000000000000000000000000000000000000000000034fb5b7000000000000000000000000000000000000000000000000000000000000006f000000000000000000000000000000000000000000000000000000000001e0f30000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000001a4000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000037000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000008d000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045000000000000000000000000000000000000000000000000000000000000000312312300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003123123000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000004cf000000000000000000000000000000000000000000000000000000000000109200000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511a",
      { formatAddress: toLowerCase },
    );
    expect(data).toMatchInlineSnapshot(`
      [
        {
          "denominator": 69n,
          "extraData": "0x123123",
          "numerator": 420n,
          "parameters": {
            "conduitKey": "0x511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511a",
            "consideration": [
              {
                "endAmount": 420n,
                "identifierOrCriteria": 69n,
                "itemType": 10,
                "recipient": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
                "startAmount": 6n,
                "token": "0x0000000000000000000000000000000000000000",
              },
              {
                "endAmount": 141n,
                "identifierOrCriteria": 55n,
                "itemType": 16,
                "recipient": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
                "startAmount": 15n,
                "token": "0x0000000000000000000000000000000000000000",
              },
            ],
            "endTime": 123123123123n,
            "offer": [
              {
                "endAmount": 420n,
                "identifierOrCriteria": 69n,
                "itemType": 10,
                "startAmount": 6n,
                "token": "0x0000000000000000000000000000000000000000",
              },
              {
                "endAmount": 11n,
                "identifierOrCriteria": 515n,
                "itemType": 10,
                "startAmount": 6n,
                "token": "0x5414d89a8bf7e99d732bc52f3e6a3ef461c0c078",
              },
              {
                "endAmount": 123123n,
                "identifierOrCriteria": 55555511n,
                "itemType": 10,
                "startAmount": 111n,
                "token": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
              },
            ],
            "offerer": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
            "orderType": 10,
            "salt": 1234123123n,
            "startTime": 123123123123n,
            "totalOriginalConsiderationItems": 69420n,
            "zone": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
            "zoneHash": "0x511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511a",
          },
          "signature": "0x123123",
        },
        [
          {
            "criteriaProof": [
              "0x511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511a",
            ],
            "identifier": 4242n,
            "index": 1231n,
            "orderIndex": 11n,
            "side": 1,
          },
        ],
        "0x511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511aaa511a",
        "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
      ]
    `);
  });
});

/* [Multicall3](https://github.com/mds1/multicall) */
const multicall3Abi = [
  {
    inputs: [
      {
        components: [
          {
            name: "target",
            type: "address",
          },
          {
            name: "allowFailure",
            type: "bool",
          },
          {
            name: "callData",
            type: "bytes",
          },
        ],
        name: "calls",
        type: "tuple[]",
      },
    ],
    name: "aggregate3",
    outputs: [
      {
        components: [
          {
            name: "success",
            type: "bool",
          },
          {
            name: "returnData",
            type: "bytes",
          },
        ],
        name: "returnData",
        type: "tuple[]",
      },
    ],
    stateMutability: "view",
    type: "function",
  },
] as const;

describe("multicall3", () => {
  test("zero data", () => {
    expect(
      decodeAbiParameters(
        multicall3Abi[0].outputs,
        "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000",
      ),
    ).toMatchInlineSnapshot(`
      [
        [
          {
            "returnData": "0x",
            "success": true,
          },
        ],
      ]
    `);
  });

  test("zero data + non-zero data", () => {
    expect(
      decodeAbiParameters(
        multicall3Abi[0].outputs,
        "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000d752bd588f61926e40000000000000000000000000000000000000000000000002e0e220d3d6cf5630000000000000000000000000000000000000000000000000000000063fa0b5f",
      ),
    ).toMatchInlineSnapshot(`
      [
        [
          {
            "returnData": "0x",
            "success": true,
          },
          {
            "returnData": "0x00000000000000000000000000000000000000000000000d752bd588f61926e40000000000000000000000000000000000000000000000002e0e220d3d6cf5630000000000000000000000000000000000000000000000000000000063fa0b5f",
            "success": true,
          },
        ],
      ]
    `);
  });
});

test("data suffix", () => {
  expect(
    decodeAbiParameters(
      [
        {
          name: "xIn",
          type: "uint256",
        },
      ],
      "0x0000000000000000000000000000000000000000000000000000000000010f2cdeadbeef",
    ),
  ).toEqual([69420n]);
});

test.skip("data size too small", () => {
  expect(() =>
    decodeAbiParameters(
      [{ type: "uint256" }],
      "0x0000000000000000000000000000000000000000000000000000000000010f",
    ),
  ).toThrowErrorMatchingInlineSnapshot(`
    [AbiDecodingDataSizeTooSmallError: Data size of 31 bytes is too small for given parameters.

    Params: (uint256)
    Data:   0x0000000000000000000000000000000000000000000000000000000000010f (31 bytes)

    Version: viem@2.30.1]
  `);

  expect(() =>
    decodeAbiParameters(
      [{ type: "uint256" }],
      "0x0000000000000000000000000000000000000000000000000000000000010f",
    ),
  ).toThrowErrorMatchingInlineSnapshot(`
    [AbiDecodingDataSizeTooSmallError: Data size of 31 bytes is too small for given parameters.

    Params: (uint256)
    Data:   0x0000000000000000000000000000000000000000000000000000000000010f (31 bytes)

    Version: viem@2.30.1]
  `);

  expect(() =>
    decodeAbiParameters(
      [{ type: "uint256" }, { type: "uint256" }],
      "0x0000000000000000000000000000000000000000000000000000000000010f2c",
    ),
  ).toThrowErrorMatchingInlineSnapshot(`
    [PositionOutOfBoundsError: Position \`32\` is out of bounds (\`0 < position < 32\`).

    Version: viem@2.30.1]
  `);
});

test("invalid type", () => {
  expect(() =>
    decodeAbiParameters(
      [{ name: "x", type: "lol" }],
      "0x0000000000000000000000000000000000000000000000000000000000000000",
    ),
  ).toThrowErrorMatchingInlineSnapshot(`
    [InvalidAbiDecodingType: Type "lol" is not a valid decoding type.
    Please provide a valid ABI type.

    Docs: https://viem.sh/docs/contract/decodeAbiParameters
    Version: viem@2.30.1]
  `);
});

test("error: zero data", () => {
  expect(() =>
    decodeAbiParameters(
      [
        {
          inputs: [],
          name: "foo",
          outputs: [
            {
              name: "x",
              type: "uint256",
            },
          ],
          stateMutability: "pure",
          type: "function",
        },
      ],
      "0x",
    ),
  ).toThrowErrorMatchingInlineSnapshot(`
    [AbiDecodingZeroDataError: Cannot decode zero data ("0x") with ABI parameters.

    Version: viem@2.30.1]
  `);
});

test("error: recursive decode array", () => {
  const payload = `0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000a${"0000000000000000000000000000000000000000000000000000000000000020".repeat(
    64,
  )}`;
  expect(() =>
    decodeAbiParameters(
      [{ type: "uint256[][][][][][][][][][]" }],
      `0x${payload}`,
    ),
  ).toThrowErrorMatchingInlineSnapshot(
    "[Error: Recursive read limit exceeded.]",
  );
});

test("zst", () => {
  const payload =
    "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000FFFFFFFF" as const;

  expect(() =>
    decodeAbiParameters([{ type: "uint256[0][4294967295]" }], payload),
  ).toThrowErrorMatchingInlineSnapshot("[Error: Invalid data length.]");
  expect(() =>
    decodeAbiParameters([{ type: "uint32[0][4294967295]" }], payload),
  ).toThrowErrorMatchingInlineSnapshot("[Error: Invalid data length.]");
  expect(() =>
    decodeAbiParameters([{ type: "uint256[4294967295][4294967295]" }], payload),
  ).toThrowErrorMatchingInlineSnapshot("[Error: Invalid data length.]");
  expect(() =>
    decodeAbiParameters([{ type: "uint32[4294967295][4294967295]" }], payload),
  ).toThrowErrorMatchingInlineSnapshot("[Error: Invalid data length.]");
  expect(() =>
    decodeAbiParameters([{ type: "uint256[0][]" }], payload),
  ).toThrowErrorMatchingInlineSnapshot("[Error: Invalid data length.]");
  expect(() =>
    decodeAbiParameters([{ type: "uint256[0][]" }], payload),
  ).toThrowErrorMatchingInlineSnapshot("[Error: Invalid data length.]");
  expect(() =>
    decodeAbiParameters([{ type: "tuple[]", components: [] }], payload),
  ).toThrowErrorMatchingInlineSnapshot("[Error: Invalid data length.]");
  expect(() =>
    decodeAbiParameters(
      [{ type: "tuple[]", components: [{ type: "tuple", components: [] }] }],
      payload,
    ),
  ).toThrowErrorMatchingInlineSnapshot("[Error: Invalid data length.]");
  expect(() =>
    decodeAbiParameters(
      [{ type: "tuple[]", components: [{ type: "uint32[0]" }] }],
      payload,
    ),
  ).toThrowErrorMatchingInlineSnapshot("[Error: Invalid data length.]");
  expect(() =>
    decodeAbiParameters(
      [
        {
          type: "tuple[]",
          components: [{ type: "tuple", components: [{ type: "uint32[0]" }] }],
        },
      ],
      payload,
    ),
  ).toThrowErrorMatchingInlineSnapshot("[Error: Invalid data length.]");
});

test.skip("recursive", () => {
  const arr2 = parseAbiParameters("uint256[][]");
  const arr4 = parseAbiParameters("uint256[][][][]");
  const arr10 = parseAbiParameters("uint256[][][][][][][][][][]");
  const a = [[[], [], [], [], [], [], [], [], [], []]] as const;
  const p = encodeAbiParameters(arr2, a);
  expect(p).toEqual(
    "0x0000000000000000000000000000000000000000000000000000000000000020" + // ptr
      "000000000000000000000000000000000000000000000000000000000000000a" + // len=10
      "0000000000000000000000000000000000000000000000000000000000000140" +
      "0000000000000000000000000000000000000000000000000000000000000160" +
      "0000000000000000000000000000000000000000000000000000000000000180" +
      "00000000000000000000000000000000000000000000000000000000000001a0" +
      "00000000000000000000000000000000000000000000000000000000000001c0" +
      "00000000000000000000000000000000000000000000000000000000000001e0" +
      "0000000000000000000000000000000000000000000000000000000000000200" +
      "0000000000000000000000000000000000000000000000000000000000000220" +
      "0000000000000000000000000000000000000000000000000000000000000240" +
      "0000000000000000000000000000000000000000000000000000000000000260" + // ptrs end (10)
      "0000000000000000000000000000000000000000000000000000000000000000" +
      "0000000000000000000000000000000000000000000000000000000000000000" +
      "0000000000000000000000000000000000000000000000000000000000000000" +
      "0000000000000000000000000000000000000000000000000000000000000000" +
      "0000000000000000000000000000000000000000000000000000000000000000" +
      "0000000000000000000000000000000000000000000000000000000000000000" +
      "0000000000000000000000000000000000000000000000000000000000000000" +
      "0000000000000000000000000000000000000000000000000000000000000000" +
      "0000000000000000000000000000000000000000000000000000000000000000" +
      "0000000000000000000000000000000000000000000000000000000000000000", // 10 values
  );

  const payload =
    `0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000a${"0000000000000000000000000000000000000000000000000000000000000020".repeat(
      64,
    )}` as const;
  expect(() =>
    decodeAbiParameters(arr10, payload),
  ).toThrowErrorMatchingInlineSnapshot(`"Recursive read limit exceeded."`);

  const ptrArr = parseAbiParameters("uint256[]");
  // Try to break check
  const p2 = encodeAbiParameters(ptrArr, [
    Array.from({ length: 10 * 1024 }, (_, j) => BigInt(j + 1) * 32n),
  ]);
  expect(() =>
    decodeAbiParameters(arr10, p2),
  ).toThrowErrorMatchingInlineSnapshot(`
    [PositionOutOfBoundsError: Position \`327744\` is out of bounds (\`0 < position < 327744\`).

    Version: viem@2.30.1]
  `);
  expect(() =>
    decodeAbiParameters(arr4, p2),
  ).toThrowErrorMatchingInlineSnapshot();
  expect(() =>
    decodeAbiParameters(arr2, p2),
  ).toThrowErrorMatchingInlineSnapshot();
});

test("recursive 2", () => {
  const arr10 = parseAbiParameters("uint256[][][][][][][][][][]");
  const a = [[], [], [], [], [], [], [], [], [], []] as const;
  const ptrArr = parseAbiParameters("uint256[]");
  const mainPtr = encodeAbiParameters(ptrArr, [
    a.map((i: any) => BigInt(a.length - i + 1) * 32n),
  ]);
  expect(() =>
    decodeAbiParameters(arr10, `0x${mainPtr.slice(2).repeat(10 + 1)}`),
  ).toThrowErrorMatchingInlineSnapshot(
    "[Error: Recursive read limit exceeded.]",
  );
});

test("struct: (uint256, string, uint256)", () => {
  const params = parseAbiParameters("(uint256 x, string, address z)");
  const data = encodeAbiParameters(params, [[2n, "hi", zeroAddress]]);

  expect(decodeAbiParameters(params, data)).toMatchInlineSnapshot(`
    [
      [
        2n,
        "hi",
        "0x0000000000000000000000000000000000000000",
      ],
    ]
  `);
});
